package club.xiaojiawei.strings;

/**
 * @author 肖嘉威
 * @version 1.0
 * @date 5/3/22 11:13 PM
 * @question 1208. 尽可能使字符串相等
 * @description 给你两个长度相同的字符串，s 和 t。
 * 将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销（开销可能为 0），也就是两个字符的 ASCII 码值的差的绝对值。
 * 用于变更字符串的最大预算是 maxCost。在转化字符串时，总开销应当小于等于该预算，这也意味着字符串的转化可能是不完全的。
 * 如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串，则返回可以转化的最大长度。
 * 如果 s 中没有子字符串可以转化成 t 中对应的子字符串，则返回 0。
 */
public class EqualSubstring1208 {

    public static void main(String[] args) {
        String s = "krpgjbjjznpzdfy", t = "nxargkbydxmsgby";
        int result = equalSubstring2(s, t, 14);
        System.out.println(result);
    }

    /**
     * 滑动窗口法
     * @param s
     * @param t
     * @param maxCost
     * @return
     */
    public static int equalSubstring(String s, String t, int maxCost) {
        int l = 0, r = 0, max = 0, count = 0;
        int[] nums = new int[s.length()];
        for (int i = 0; i < s.length(); i++) {
            nums[i] = Math.abs(s.charAt(i) - t.charAt(i));
        }
        while (r < s.length()){
            if ((count += nums[r]) > maxCost){
                max = Math.max(max, r - l);
                do {
                    count -= nums[l];
                    l++;
                }while (count > maxCost);
            }
            r++;
        }
        return Math.max(max, r - l);
    }

    /**
     * 官方-前缀和 + 二分查找
     * @param s
     * @param t
     * @param maxCost
     * @return
     */
    public static int equalSubstring2(String s, String t, int maxCost) {
        int n = s.length();
        int[] accDiff = new int[n + 1];
        for (int i = 0; i < n; i++) {
            accDiff[i + 1] = accDiff[i] + Math.abs(s.charAt(i) - t.charAt(i));
        }
        int maxLength = 0;
        for (int i = 1; i <= n; i++) {
            int start = binarySearch(accDiff, i, accDiff[i] - maxCost);
            maxLength = Math.max(maxLength, i - start);
        }
        return maxLength;
    }

    /**
     * 二分查找-若没有对应数则返回应该插入的位置
     * @param accDiff
     * @param endIndex
     * @param target
     * @return
     */
    public static int binarySearch(int[] accDiff, int endIndex, int target) {
        int low = 0, high = endIndex;
        while (low < high){
            int mid = (low + high) >> 1;
            if (target > accDiff[mid]){
                low = mid + 1;
            }else {
                high = mid;
            }
        }
        return low;
    }

}
